#include "down_and_up.h"


// 客户端上传文件（支持断点续传）
int upload_file(int sockfd, const char *filename) {
    // 1. 计算文件哈希
    char file_hash[65];
    sha256_file(filename, file_hash);
    printf("[Client] File hash: %s\n", file_hash);

    // 2. 发送哈希给服务端检查是否已存在
    train_t packet;
    strncpy(packet.hash, file_hash, sizeof(packet.hash));
    send(sockfd, &packet, sizeof(packet), 0);

    // 3. 接收服务端响应（是否需上传）
    int need_upload;
    recv(sockfd, &need_upload, sizeof(need_upload), 0);
    if (!need_upload) {
        printf("[Client] File already exists on server (skipping upload)\n");
        return 0;
    }

    // 4. 获取本地文件大小
    struct stat st;
    stat(filename, &st);
    off_t file_size = st.st_size;

    // 5. 发送文件名和大小
    strncpy(packet.data, filename, sizeof(packet.data));
    packet.length = sizeof(file_size);
    memcpy(packet.data + strlen(filename) + 1, &file_size, sizeof(file_size));
    send(sockfd, &packet, sizeof(packet), 0);

    // 6. 断点续传：获取已上传的偏移量
    off_t offset;
    recv(sockfd, &offset, sizeof(offset), 0);
    printf("[Client] Resuming upload from offset: %ld\n", offset);

    // 7. 分块上传文件
    int fd = open(filename, O_RDONLY);
    lseek(fd, offset, SEEK_SET);  // 跳转到断点位置

    while (offset < file_size) {
        ssize_t bytes_read = read(fd, packet.data, sizeof(packet.data));
        packet.length = bytes_read;
        send(sockfd, &packet, sizeof(packet), 0);
        offset += bytes_read;
    }

    // 8. 发送结束标志
    packet.length = 0;
    send(sockfd, &packet, sizeof(packet), 0);
    close(fd);
    return 0;
}




// 服务端接收文件（支持断点续传和哈希校验）
int receive_file(int sockfd) {
    train_t packet;
    
    // 1. 接收客户端发送的哈希
    recv(sockfd, &packet, sizeof(packet), 0);
    char *file_hash = packet.hash;

    // 2. 检查哈希是否已存在
    int file_exists = db_check_hash(file_hash);
    send(sockfd, &file_exists, sizeof(file_exists), 0);
    if (file_exists) {
        printf("[Server] File already exists (hash: %s)\n", file_hash);
        return 0;
    }

    // 3. 接收文件名和大小
    recv(sockfd, &packet, sizeof(packet), 0);
    char *filename = packet.data;
    off_t file_size;
    memcpy(&file_size, packet.data + strlen(filename) + 1, sizeof(file_size));

    // 4. 断点续传：检查已接收的字节数
    char filepath[256];
    snprintf(filepath, sizeof(filepath), "server_storage/%s", filename);
    off_t offset = 0;

    struct stat st;
    if (stat(filepath, &st) == 0) {
        offset = st.st_size;  // 文件已部分存在
    }
    send(sockfd, &offset, sizeof(offset), 0);

    // 5. 接收文件数据
    int fd = open(filepath, O_WRONLY | O_CREAT | (offset ? O_APPEND : O_TRUNC), 0666);
    lseek(fd, offset, SEEK_SET);

    while (1) {
        recv(sockfd, &packet, sizeof(packet), 0);
        if (packet.length == 0) break;  // 结束标志
        write(fd, packet.data, packet.length);
    }
    close(fd);

    // 6. 校验文件哈希
    char server_hash[65];
    sha256_file(filepath, server_hash);
    if (strcmp(server_hash, file_hash) != 0) {
        printf("[Server] Hash mismatch! File may be corrupted.\n");
        unlink(filepath);  // 删除无效文件
        return -1;
    }

    // 7. 写入数据库
    db_insert_file(filename, filepath, file_size, file_hash);
    printf("[Server] File saved: %s\n", filepath);
    return 0;
}




// 客户端从服务端下载文件
int download_file(int sockfd, const char *filename, const char *save_path) {
    train_t packet;

    // 1. 发送下载请求（文件名）
    strncpy(packet.data, filename, sizeof(packet.data));
    packet.length = strlen(filename);
    send(sockfd, &packet, sizeof(packet), 0);

    // 2. 接收文件大小和哈希（服务端先校验是否存在）
    recv(sockfd, &packet, sizeof(packet), 0);
    if (packet.length == -1) {
        printf("[Client] Error: File not found on server.\n");
        return -1;
    }

    off_t file_size;
    memcpy(&file_size, packet.data, sizeof(file_size));
    char *file_hash = packet.hash;
    printf("[Client] Downloading file: %s (Size: %ld, Hash: %s)\n", filename, file_size, file_hash);

    // 3. 断点续传：检查本地已下载部分
    off_t offset = 0;
    struct stat st;
    if (stat(save_path, &st) == 0) {
        offset = st.st_size;
        printf("[Client] Resuming download from offset: %ld\n", offset);
    }
    send(sockfd, &offset, sizeof(offset), 0);

    // 4. 接收文件数据
    int fd = open(save_path, O_WRONLY | O_CREAT | (offset ? O_APPEND : O_TRUNC), 0666);
    lseek(fd, offset, SEEK_SET);

    while (offset < file_size) {
        recv(sockfd, &packet, sizeof(packet), 0);
        if (packet.length <= 0) break;
        write(fd, packet.data, packet.length);
        offset += packet.length;
        printf("\rProgress: %.2f%%", (float)offset / file_size * 100);
        fflush(stdout);
    }
    close(fd);
    printf("\n[Client] Download complete.\n");

    // 5. 校验文件哈希
    char local_hash[65];
    sha256_file(save_path, local_hash);
    if (strcmp(local_hash, file_hash) != 0) {
        printf("[Client] Error: File corrupted (hash mismatch)!\n");
        unlink(save_path);
        return -1;
    }
    return 0;
}



// 服务端处理客户端下载请求
int handle_download(int sockfd) {
    train_t packet;

    // 1. 接收客户端请求的文件名
    recv(sockfd, &packet, sizeof(packet), 0);
    char *filename = packet.data;
    printf("[Server] Client requested file: %s\n", filename);

    // 2. 检查文件是否存在
    char filepath[256];
    snprintf(filepath, sizeof(filepath), "server_storage/%s", filename);
    struct stat st;
    if (stat(filepath, &st) != 0) {
        packet.length = -1;  // 文件不存在标志
        send(sockfd, &packet, sizeof(packet), 0);
        return -1;
    }

    // 3. 发送文件大小和哈希（从数据库读取）
    off_t file_size = st.st_size;
    char file_hash[65];
    get_file_hash_from_db(filename, file_hash);  // 假设已实现该函数

    memcpy(packet.data, &file_size, sizeof(file_size));
    strncpy(packet.hash, file_hash, sizeof(packet.hash));
    packet.length = sizeof(file_size);
    send(sockfd, &packet, sizeof(packet), 0);

    // 4. 接收客户端断点偏移量
    off_t offset;
    recv(sockfd, &offset, sizeof(offset), 0);
    printf("[Server] Client resuming from offset: %ld\n", offset);

    // 5. 分块发送文件数据
    int fd = open(filepath, O_RDONLY);
    lseek(fd, offset, SEEK_SET);

    while (offset < file_size) {
        ssize_t bytes_read = read(fd, packet.data, sizeof(packet.data));
        packet.length = bytes_read;
        send(sockfd, &packet, sizeof(packet), 0);
        offset += bytes_read;
    }

    // 6. 发送结束标志
    packet.length = 0;
    send(sockfd, &packet, sizeof(packet), 0);
    close(fd);
    return 0;
}

